using System;
using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace TMFileManager {
    public partial class TreeMap : UserControl {
        private TreeMapNode root = new TreeMapNode("");
        private TreeMapNode highLighted = null;
        private bool highLightedIsDir = false;
        private bool showFreeSpace = false;

        public event EventHandler RootPathChanged;

        private Hashtable extensions = new Hashtable();
        private System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
        private Pen red2 = new Pen(Color.Red, 2);
        private Pen yellow2 = new Pen(Color.Yellow, 2);
        private Image buffer = null;
        private Graphics bufferGraphics = null;
        private bool repaint = true;
        private Font f = new Font("Ms Sans Serif", 9);

        private int depthLevel = 0;
        private TreeMapNode clipBoard;
        private bool cutClipboard = false;

        private bool editing = false;

        public int DepthLevel {
            get {
                return depthLevel;
            }
            set {
                if (value != depthLevel) {
                    depthLevel = value;
                    RootPath = RootPath;
                }
            }
        }

        public bool ShowFreeSpace {
            get {
                return showFreeSpace;
            }
            set {
                if (value != showFreeSpace) {
                    showFreeSpace = value;
                    RootPath = RootPath;
                }
            }
        }

        public TreeMap() {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.UserPaint, true);
            //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            if (!DesignMode) {
                ReloadColorScheme();
            }
            InitializeComponent();
        }

        public void ReloadColorScheme() {
            ColorScheme colorScheme = new ColorScheme();
            if (File.Exists(Path.Combine(Application.StartupPath, "ColorScheme.xml")))
            {
                colorScheme.ReadXml(Path.Combine(Application.StartupPath, "ColorScheme.xml"));
                foreach (ColorScheme.ColorSchemeRow cs in colorScheme._ColorScheme.Rows)
                {
                    extensions[cs.Extension.ToLower()] = Color.FromArgb(cs.A, cs.R, cs.G, cs.B);
                }
            }
        }

        public string RootPath {
            get {
                return root.getLabel();
            }
            set {
                Cursor c = Cursor;
                Cursor = Cursors.WaitCursor;
                highLighted = null;
                if (value != "") {
                    if (!DesignMode) {
                        root = new TreeMapNode(value);
                        root.setWidth(Width - 1);
                        root.setHeight(Height - 1);
                        if (showFreeSpace && Path.GetPathRoot(value) == value) {
                            //DriveInfo di = new DriveInfo(value);
                            TreeMapNode freeSpace = new TreeMapNode("Free space", 0, new DefaultValue(0));
                            root.add(freeSpace);
                            root.setWeight(populateTree(root) + freeSpace.getWeight());
                        } else {
                            root.setWeight(populateTree(root));
                        }
                        root.setValue(new DefaultValue(root.getWeight()));
                        SplitSquarified ss = new SplitSquarified();
                        ss.setBorder(0);
                        ss.calculatePositions(root);
                        repaint = true;
                        Invalidate();
                    }
                    if (RootPathChanged != null) {
                        RootPathChanged(this, new EventArgs());
                    }
                }
                Cursor = c;
            }
        }

        protected override void OnPaint(PaintEventArgs e) {
            if (repaint) {
                if (buffer == null) {
                    buffer = new Bitmap(ClientSize.Width, ClientSize.Height, e.Graphics);
                    bufferGraphics = Graphics.FromImage(buffer);
                }
                paint(root, bufferGraphics, 0);
                repaint = false;
            }

            e.Graphics.DrawImageUnscaled(buffer, 0, 0);
            if (highLighted != null) {
                if (highLightedIsDir) {
                    e.Graphics.DrawRectangle(yellow2, highLighted.Bounds);
                } else if (highLighted.Parent != null) {
                    e.Graphics.DrawRectangle(yellow2, highLighted.Parent.Bounds);
                }
                if (!highLightedIsDir) {
                    e.Graphics.DrawRectangle(Pens.Red, (int)Math.Round(highLighted.getX()), (int)Math.Round(highLighted.getY()),
                        (int)Math.Round(highLighted.getWidth() - 1D), (int)Math.Round(highLighted.getHeight() - 1D));
                }
            }
        }

        private void paint(TreeMapNode n, Graphics g, int level) {
            if (n.IsLeaf) {
                RectangleF rect = new RectangleF((float)n.getX(), (float)n.getY(), (float)n.getWidth(), (float)n.getHeight());
                if (rect.Width > 0 && rect.Height > 0) {
                    gp.Reset();
                    gp.AddEllipse(rect.Left - rect.Width / 4, rect.Top - rect.Height / 4, rect.Width + 2 * rect.Width / 4,
                        rect.Height + 2 * rect.Height / 4);
                    PathGradientBrush pgb = new PathGradientBrush(gp);
                    pgb.CenterColor = Color.White;
                    string ext = Path.GetExtension(n.getLabel()).TrimStart('.');
                    if (extensions.ContainsKey(ext.ToLower())) {
                        pgb.SurroundColors = new Color[] { (Color)extensions[ext.ToLower()] };
                    } else {
                        Color c = Color.FromKnownColor((KnownColor) ((int)KnownColor.ForestGreen + extensions.Count));
                        extensions[ext.ToLower()] = c;
                        pgb.SurroundColors = new Color[] { c };
                    }
                    pgb.CenterPoint = new PointF(rect.Left + rect.Width / 4, rect.Top + rect.Height / 2);

                    g.FillRectangle(pgb, rect);
                    pgb.Dispose();

                    string label = Path.GetFileName(n.getLabel());
                    SizeF labelSize = g.MeasureString(label, f, (int)rect.Width);

                    if (rect.Width > 1 && rect.Height > 1 && File.Exists(n.getLabel())) {
                        if (n.Icon == null) {
                            n.Icon = Icon.ExtractAssociatedIcon(n.getLabel());
                        }
                        if (rect.Width >= n.Icon.Width && rect.Height >= n.Icon.Height + labelSize.Height) {
                            Rectangle iconRect = new Rectangle((int)rect.Left + (int)rect.Width / 2 - n.Icon.Width / 2,
                                (int)rect.Top + (int)rect.Height / 2 - n.Icon.Height / 2 - (int)labelSize.Height / 2, n.Icon.Width, n.Icon.Height);
                            if (clipBoard == n && cutClipboard) {
                                ImageAttributes ia = new ImageAttributes();
                                ia.SetGamma(0.3F);
                                g.DrawImage(n.Icon.ToBitmap(), iconRect, 0, 0, n.Icon.Width, n.Icon.Height, GraphicsUnit.Pixel, ia);
                            } else {
                                g.DrawIconUnstretched(n.Icon, iconRect);
                            }
                            Region clip = g.Clip;
                            g.Clip = new Region(rect);
                            g.DrawString(label, f, Brushes.Black, new RectangleF(rect.Left + rect.Width / 2 - labelSize.Width / 2,
                                rect.Top + rect.Height / 2 - labelSize.Height / 2 + iconRect.Height / 2, labelSize.Width, labelSize.Height));
                            g.Clip = clip;
                        } else {
                            double ratio = Math.Min(rect.Width / n.Icon.Width, rect.Height / n.Icon.Height);
                            if (clipBoard == n && cutClipboard) {
                                ImageAttributes ia = new ImageAttributes();
                                ia.SetGamma(0.3F);
                                g.DrawImage(n.Icon.ToBitmap(), new Rectangle((int)Math.Round(rect.Left + rect.Width / 2 - n.Icon.Width * ratio / 2),
                                    (int)Math.Round(rect.Top + rect.Height / 2 - n.Icon.Height * ratio / 2),
                                    (int)Math.Round(n.Icon.Width * ratio), (int)Math.Round(n.Icon.Height * ratio)), 0, 0, n.Icon.Width, n.Icon.Height,
                                    GraphicsUnit.Pixel, ia);
                            } else {
                                g.DrawIcon(n.Icon, new Rectangle((int)Math.Round(rect.Left + rect.Width / 2 - n.Icon.Width * ratio / 2),
                                    (int)Math.Round(rect.Top + rect.Height / 2 - n.Icon.Height * ratio / 2),
                                    (int)Math.Round(n.Icon.Width * ratio), (int)Math.Round(n.Icon.Height * ratio)));
                            }
                        }
                    }
                }
            } else if (level == Properties.Settings.Default.DepthLevel) {
                RectangleF rect = new RectangleF((float)n.getX(), (float)n.getY(), (float)n.getWidth(), (float)n.getHeight());
                if (rect.Width > 0 && rect.Height > 0) {
                    gp.Reset();
                    gp.AddEllipse(rect.Left - rect.Width / 4, rect.Top - rect.Height / 4, rect.Width + 2 * rect.Width / 4,
                        rect.Height + 2 * rect.Height / 4);
                    PathGradientBrush pgb = new PathGradientBrush(gp);
                    pgb.CenterColor = Color.White;
                    pgb.SurroundColors = new Color[] { Color.YellowGreen };
                    pgb.CenterPoint = new PointF(rect.Left + rect.Width / 4, rect.Top + rect.Height / 2);

                    g.FillRectangle(pgb, rect);
                    pgb.Dispose();

                    string label = Path.GetFileName(n.getLabel());
                    SizeF labelSize = g.MeasureString(label, f);
                    Region clip = g.Clip;
                    g.Clip = new Region(rect);
                    g.DrawString(label, f, Brushes.Black, new RectangleF(rect.Left + rect.Width / 2 - labelSize.Width / 2,
                        rect.Top + rect.Height / 2 - labelSize.Height / 2, labelSize.Width, labelSize.Height));
                    g.Clip = clip;
                }
            }
            if (depthLevel == 0 || level < depthLevel) {
                foreach (TreeMapNode child in n.Nodes) {
                    paint(child, g, level + 1);
                }
            }
        }

        protected override void OnMouseMove(MouseEventArgs e) {
            base.OnMouseMove(e);
            if (!editing) {
                lock (this) {
                    Focus();
                    TreeMapNode node = null;
                    if (highLighted != null && highLighted.Parent != null) {
                        node = highLighted;
                    }
                    setTip(root, e, 0);

                    if (node != null && node != highLighted) {
                        Region reg = new Region(new Rectangle((int)Math.Round(node.getX() - 1D), (int)Math.Round(node.getY() - 1D), (int)Math.Round(node.getWidth() + 4D), 3));
                        reg.Union(new Rectangle((int)Math.Round(node.getX() - 1D), (int)Math.Round(node.getY() + node.getHeight() - 1D), (int)Math.Round(node.getWidth() + 4D), 3));
                        reg.Union(new Rectangle((int)Math.Round(node.getX() - 1D), (int)Math.Round(node.getY() - 1D), 3, (int)Math.Round(node.getHeight() + 4D)));
                        reg.Union(new Rectangle((int)Math.Round(node.getX() + node.getWidth() - 2D), (int)Math.Round(node.getY()), 3, (int)Math.Round(node.getHeight()) + 4));
                        Invalidate(reg);
                        node = node.Parent;
                        if (node != null) {
                            reg = new Region(new Rectangle((int)Math.Round(node.getX() - 1D), (int)Math.Round(node.getY() - 1D), (int)Math.Round(node.getWidth() + 4D), 3));
                            reg.Union(new Rectangle((int)Math.Round(node.getX() - 1D), (int)Math.Round(node.getY() + node.getHeight() - 1D), (int)Math.Round(node.getWidth() + 4D), 3));
                            reg.Union(new Rectangle((int)Math.Round(node.getX() - 1D), (int)Math.Round(node.getY() - 1D), 3, (int)Math.Round(node.getHeight() + 4D)));
                            reg.Union(new Rectangle((int)Math.Round(node.getX() + node.getWidth() - 1D), (int)Math.Round(node.getY()), 3, (int)Math.Round(node.getHeight()) + 4));
                            Invalidate(reg);
                        }
                    }
                    if (highLighted != null && highLighted.Parent != null && node != highLighted) {
                        node = highLighted.Parent;
                        Region reg = new Region(new Rectangle((int)Math.Round(node.getX()), (int)Math.Round(node.getY()), (int)Math.Round(node.getWidth() + 4D), 3));
                        reg.Union(new Rectangle((int)Math.Round(node.getX()), (int)Math.Round(node.getY() + node.getHeight() - 1D), (int)Math.Round(node.getWidth() + 4D), 3));
                        reg.Union(new Rectangle((int)Math.Round(node.getX()), (int)Math.Round(node.getY()), 3, (int)Math.Round(node.getHeight() + 4D)));
                        reg.Union(new Rectangle((int)Math.Round(node.getX() + node.getWidth() - 1D), (int)Math.Round(node.getY()), 3, (int)Math.Round(node.getHeight() + 4D)));
                        Invalidate(reg);
                        node = highLighted;
                        reg = new Region(new Rectangle((int)Math.Round(node.getX()), (int)Math.Round(node.getY()), (int)Math.Round(node.getWidth() + 4D), 3));
                        reg.Union(new Rectangle((int)Math.Round(node.getX()), (int)Math.Round(node.getY() + node.getHeight() - 1D), (int)Math.Round(node.getWidth() + 4D), 3));
                        reg.Union(new Rectangle((int)Math.Round(node.getX()), (int)Math.Round(node.getY()), 3, (int)Math.Round(node.getHeight() + 4D)));
                        reg.Union(new Rectangle((int)Math.Round(node.getX() + node.getWidth() - 2D), (int)Math.Round(node.getY()), 3, (int)Math.Round(node.getHeight() + 4D)));
                        Invalidate(reg);
                    }
                    Update();
                }
            }
        }

        private string createNodeTip(TreeMapNode n) {
            string label;
            if (n.getWeight() < 1024D) {
                label = n.getLabel() + "\n" + (int)n.getWeight() + " B";
            } else if (n.getWeight() < 1024D * 1024D) {
                label = n.getLabel() + "\n" + (int)(n.getWeight() / 1024D) + " KB";
            } else if (n.getWeight() < 1024D * 1024D * 1024D) {
                label = n.getLabel() + "\n" + string.Format("{0:#.##}", n.getWeight() / (1024D * 1024D)) + " MB";
            } else {
                label = n.getLabel() + "\n" + string.Format("{0:#.##}", n.getWeight() / (1024D * 1024D * 1024D)) + " GB";
            }
            return label;
        }

        private void setTip(TreeMapNode n, MouseEventArgs e, int level) {
            string label = createNodeTip(n);
            if (n.IsLeaf && n.Bounds.Contains(e.X, e.Y)) {
                if (depthLevel == 0 || level <= depthLevel) {
                    if (toolTip1.GetToolTip(this) != label) {
                        toolTip1.SetToolTip(this, label);
                        if (n.Parent != null) {
                            highLighted = n;
                            highLightedIsDir = false;
                        }
                    }
                } else {
                    if (n.Parent != null) {
                        label = createNodeTip(n.Parent);
                        if (toolTip1.GetToolTip(this) != label) {
                            toolTip1.SetToolTip(this, label);
                            highLighted = n.Parent;
                            highLightedIsDir = true;
                        }
                    }
                }
            } else {
                if (depthLevel == 0 || level <= depthLevel) {
                    foreach (TreeMapNode child in n.Nodes) {
                        setTip(child, e, level + 1);
                    }
                } else if (n.Bounds.Contains(e.X, e.Y)) {
                    label = createNodeTip(n.Parent);
                    if (toolTip1.GetToolTip(this) != label) {
                        toolTip1.SetToolTip(this, label);
                        highLighted = n.Parent;
                        highLightedIsDir = true;
                    }
                }
            }
        }

        protected override void OnSizeChanged(EventArgs e) {
            if (buffer != null) {
                buffer.Dispose();
            }
            if (Width > 0 && Height > 0) {
                buffer = new Bitmap(Width, Height, CreateGraphics());
                if (bufferGraphics != null) {
                    bufferGraphics.Dispose();
                }
                bufferGraphics = Graphics.FromImage(buffer);
                Cursor c = Cursor;
                Cursor = Cursors.WaitCursor;
                SplitSquarified ss = new SplitSquarified();
                ss.setBorder(0);
                root.setWidth(Width);
                root.setHeight(Height);
                if (!DesignMode) {
                    ss.calculatePositions(root);
                }
                repaint = true;
                Cursor = c;
                Invalidate();
            }
            base.OnSizeChanged(e);
        }

        private long populateTree(TreeMapNode root) {
            DirectoryInfo d = new DirectoryInfo(root.getLabel());
            try {
                long size = 0L;
                foreach (DirectoryInfo dir in d.GetDirectories()) {
                    TreeMapNode node = new TreeMapNode(dir.FullName);
                    long weight = populateTree(node);
                    node.setWeight(weight);
                    node.setValue(new DefaultValue(weight));
                    root.add(node);
                    size += weight;
                }
                foreach (FileInfo file in d.GetFiles()) {
                    size += file.Length;
                    TreeMapNode node = new TreeMapNode(file.FullName, file.Length, new DefaultValue(file.Length));
                    root.add(node);
                }
                return size;
            } catch {
                return 0;
            }
        }

        protected override void OnDoubleClick(EventArgs e) {
            base.OnDoubleClick(e);
            if (highLighted != null) {
                if (highLightedIsDir) {
                    RootPath = highLighted.getLabel();
                } else if (File.Exists(highLighted.getLabel())) {
                    System.Diagnostics.Process.Start(highLighted.getLabel());
                }
            }
        }

        protected override void OnMouseWheel(MouseEventArgs e) {
            base.OnMouseWheel(e);
            if (e.Delta > 0) {
                if (highLighted != null) {
                    RootPath = highLighted.Parent.getLabel();
                }
            } else {
                string path = Path.GetDirectoryName(RootPath);
                if (path != null) {
                    RootPath = path;
                }
            }
        }

        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e) {
            PropertiesDialog pd = new PropertiesDialog(highLighted);
            pd.ShowDialog();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e) {
            System.Diagnostics.Process.Start(highLighted.getLabel());
        }

        private void copyToolStripMenuItem_Click(object sender, EventArgs e) {
            clipBoard = highLighted;
            cutClipboard = false;
        }

        private void pasteToolStripMenuItem_Click(object sender, EventArgs e) {
            if (clipBoard != null) {
                CopyFile cf = new CopyFile(cutClipboard);
                cf.SourceFile = clipBoard.getLabel();
                if (File.Exists(highLighted.getLabel())) {
                    cf.DestinationFile = Path.Combine(Path.GetDirectoryName(highLighted.getLabel()), Path.GetFileName(clipBoard.getLabel()));
                } else if (Directory.Exists(highLighted.getLabel())) {
                    cf.DestinationFile = Path.Combine(highLighted.getLabel(), Path.GetFileName(clipBoard.getLabel()));
                }
                if (cf.ShowDialog() == DialogResult.OK) {
                    RootPath = RootPath;
                }
                if (cutClipboard) {
                    clipBoard = null;
                }
            }
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e) {
            if (highLighted != null && MessageBox.Show("Are you sure you want to delete the file " + highLighted.getLabel() + " ?", "File delete",
                MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) {
                File.Delete(highLighted.getLabel());
            }
        }

        private void TreeMap_DragDrop(object sender, DragEventArgs e) {
            TreeMapNode node = (TreeMapNode)e.Data.GetData(typeof(TreeMapNode));
            Point clientPoint = PointToClient(new Point(e.X, e.Y));
            TreeMapNode target = FindNodeAt(root, clientPoint.X, clientPoint.Y, 0);

            if (node != null && target != null) {
                switch (e.Effect) {
                    case DragDropEffects.Copy :
                        CopyFile cf = new CopyFile();
                        cf.SourceFile = node.getLabel();
                        if (File.Exists(target.getLabel())) {
                            cf.DestinationFile = Path.Combine(Path.GetDirectoryName(target.getLabel()), Path.GetFileName(node.getLabel()));
                        } else if (Directory.Exists(target.getLabel())) {
                            cf.DestinationFile = Path.Combine(target.getLabel(), Path.GetFileName(node.getLabel()));
                        }
                        if (cf.ShowDialog() == DialogResult.OK) {
                            RootPath = RootPath;
                        }
                        break;
                    case DragDropEffects.Move :
                        cf = new CopyFile(true);
                        cf.SourceFile = node.getLabel();
                        if (File.Exists(target.getLabel())) {
                            cf.DestinationFile = Path.Combine(Path.GetDirectoryName(target.getLabel()), Path.GetFileName(node.getLabel()));
                        } else if (Directory.Exists(target.getLabel())) {
                            cf.DestinationFile = Path.Combine(target.getLabel(), Path.GetFileName(node.getLabel()));
                        }
                        if (cf.ShowDialog() == DialogResult.OK) {
                            RootPath = RootPath;
                        }
                        break;
                    case DragDropEffects.Link :
                        break;
                }
            }
        }

        private TreeMapNode FindNodeAt(TreeMapNode root, int x, int y, int level) {
            if (root.Bounds.Contains(x, y)) {
                if (depthLevel == 0 || level < depthLevel) {
                    foreach (TreeMapNode node in root.Nodes) {
                        TreeMapNode n = FindNodeAt(node, x, y, level + 1);
                        if (n != null) {
                            return n;
                        }
                    }
                    return root;
                } else {
                    return root;
                }
            } else {
                return null;
            }
        }

        private void TreeMap_MouseMove(object sender, MouseEventArgs e) {
            if (e.Button == MouseButtons.Left && highLighted != null) {
                DoDragDrop(highLighted, DragDropEffects.All);
            }
        }

        private void TreeMap_DragOver(object sender, DragEventArgs e) {
            TreeMapNode node = e.Data.GetData(typeof(TreeMapNode)) as TreeMapNode;
            Point clientPoint = PointToClient(new Point(e.X, e.Y));
            if (node != null) {
                TreeMapNode target = FindNodeAt(root, clientPoint.X, clientPoint.Y, 0);
                if (target != null) {
                    highLighted = target;
                    Invalidate();
                }
                if ((e.KeyState & 4) == 4 && !node.Bounds.Contains(clientPoint)) {
                    e.Effect = DragDropEffects.Move;
                } else if (!node.Bounds.Contains(clientPoint)) {
                    e.Effect = DragDropEffects.Copy;
                } else {
                    e.Effect = DragDropEffects.None;
                }
            }
        }

        private void cutToolStripMenuItem_Click(object sender, EventArgs e) {
            clipBoard = highLighted;
            cutClipboard = true;
            repaint = true;
            Invalidate();
        }

        private void renameToolStripMenuItem_Click(object sender, EventArgs e) {
            TextBox tb = new TextBox();
            tb.LostFocus += new EventHandler(tb_LostFocus);
            tb.KeyPress += new KeyPressEventHandler(tb_KeyPress);
            Rectangle textRect;
            string filename = Path.GetFileName(highLighted.getLabel());
            tb.Tag = highLighted;
            tb.Text = filename;
            SizeF labelSize = CreateGraphics().MeasureString(filename, f);
            if (!highLightedIsDir) {
                Icon icon = Icon.ExtractAssociatedIcon(highLighted.getLabel());
                if (highLighted.Bounds.Width >= icon.Width && highLighted.Bounds.Height >= icon.Height + tb.Height) {
                    Rectangle iconRect = new Rectangle((int)highLighted.Bounds.Left + (int)highLighted.Bounds.Width / 2 - icon.Width / 2,
                        (int)highLighted.Bounds.Top + (int)highLighted.Bounds.Height / 2 - icon.Height / 2 - (int)tb.Height / 2,
                        icon.Width, icon.Height);
                    textRect = new Rectangle(highLighted.Bounds.Left + highLighted.Bounds.Width / 2 - (int)labelSize.Width / 2,
                        highLighted.Bounds.Top + highLighted.Bounds.Height / 2 - (int)labelSize.Height / 2 + iconRect.Height / 2,
                        (int)labelSize.Width, (int)labelSize.Height);
                } else {
                    textRect = new Rectangle(highLighted.Bounds.Left + highLighted.Bounds.Width / 2 - (int)labelSize.Width / 2,
                        highLighted.Bounds.Top + highLighted.Bounds.Height / 2 - (int)labelSize.Height / 2,
                        (int)labelSize.Width, (int)labelSize.Height);
                }
            } else {
                textRect = new Rectangle(highLighted.Bounds.Left + highLighted.Bounds.Width / 2 - (int)labelSize.Width / 2,
                        highLighted.Bounds.Top + highLighted.Bounds.Height / 2 - (int)labelSize.Height / 2,
                        (int)labelSize.Width, (int)labelSize.Height);
            }
            tb.Bounds = textRect;
            tb.Font = f;
            editing = true;
            Controls.Add(tb);
            tb.Focus();
        }

        void tb_KeyPress(object sender, KeyPressEventArgs e) {
            if (e.KeyChar == 27) {
                ((TextBox)sender).Text = Path.GetFileName(highLighted.getLabel());
                Focus();
            } else if (e.KeyChar == '\r') {
                Focus();
            }
        }

        void tb_LostFocus(object sender, EventArgs e) {
            TreeMapNode node = (TreeMapNode)((TextBox)sender).Tag;
            if (Path.GetFileName(node.getLabel()) != ((TextBox)sender).Text) {
                string newPath = Path.Combine(Path.GetDirectoryName(node.getLabel()), ((TextBox)sender).Text);
                File.Move(node.getLabel(), newPath);
                node.setLabel(newPath);
                Controls.Remove((TextBox)sender);
                repaint = true;
                Invalidate();
            } else {
                Controls.Remove((TextBox)sender);
            }
            editing = false;
        }
    }
}
